﻿using System;
using System.AddIn;
using System.Globalization;
using System.IO;
using System.Text;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Markup;
using System.Xml;
using Bookvar.AddIns.AddInViews;
using Bookvar.Common;
using Bookvar.ObjectModel;

namespace Bookvar.AddIns.MindManagerImport
{
    [AddIn( "Bookvar Import AddIn", Version = "1.0.0.0" )]
    public class MindManagerImportAddin : EditableBookvarAddinView
    {
        public override Topic Execute( Topic topic )
        {
            OpenFileDialog fileDialog = new OpenFileDialog();
            fileDialog.Filter =
                "MindManager 7 Xml (*.xml, *.xmmap)|*.xml;*.xmmap|MindManager 6 (*.mmap)|*.mmap|All Files (*.*)|*.*";
            fileDialog.FilterIndex = 1;
            if ( fileDialog.ShowDialog() == DialogResult.OK )
            {
                string fileToImport = fileDialog.FileName;
                string extension = Path.GetExtension( fileToImport );
                switch ( extension.ToLower( CultureInfo.InvariantCulture ) )
                {
                    case ".xml" :
                    case ".xmmap" :
                    {
                        topic = GetTopicFromFile( fileToImport );
                        break;
                    }
                    case ".mmap" :
                    {
                        string path = ExtractFile( fileToImport );
                        topic = GetTopicFromFile( Path.Combine( path, "Document.xml" ) );
                        Directory.Delete( path, true );

                        break;
                    }
                }
                return topic;
            }
            return null;
        }

        private static string ExtractFile( string fileToImport )
        {
            string tempPath = Path.GetTempPath() + Guid.NewGuid();
            ZipHelper.ExtractZip( fileToImport, tempPath );
            return tempPath;
        }

        private static Topic GetTopicFromFile( string fileToImport )
        {
            using ( StreamReader map = new StreamReader( fileToImport ) )
            {
                Topic topic = new Topic();
                XmlDocument doc = new XmlDocument();
                doc.LoadXml( map.ReadToEnd() );
                XmlNamespaceManager nsManager = CreateListItemNsMgr( doc.NameTable );
                XmlNode mainNode = doc.SelectSingleNode( "/ap:Map/ap:OneTopic/ap:Topic", nsManager );
                ParseNode( mainNode, nsManager, topic, ( new FileInfo( fileToImport ) ).DirectoryName );
                return topic;
            }
        }

        private static void ParseNode( XmlNode node, XmlNamespaceManager nsManager, Topic topic, string path )
        {
            XmlNode textNode = node.SelectSingleNode( "./ap:Text", nsManager );
            string text = String.Empty;
            if ( textNode != null && textNode.Attributes[ "PlainText" ] != null )
            {
                text = textNode.Attributes[ "PlainText" ].Value;
            }

            topic.Name = text;
            XmlNode imageNode = node.SelectSingleNode( "./ap:OneImage/ap:Image/ap:ImageData", nsManager );
            if ( imageNode != null )
            {
                string type = imageNode.Attributes[ "ImageType" ].Value;
                switch ( type )
                {
                    case "urn:mindjet:PngImage" :
                    {
                        Resource image = new Resource();
                        image.ResourceType = ResourceType.Image;

                        XmlNode imageData = imageNode.SelectSingleNode( "./cor:Base64", nsManager );
                        if ( imageData != null )
                        {
                            string imageBase64String =
                                imageNode.SelectSingleNode( "./cor:Base64", nsManager ).InnerText.Trim();


                            byte[] bitmapData = Convert.FromBase64String( imageBase64String );
                            //System.IO.MemoryStream streamBitmap = new System.IO.MemoryStream(bitmapData);


                            image.ResourceBytes = bitmapData;
                        }
                        else
                        {
                            string imageUri = imageNode.SelectSingleNode( "./cor:Uri", nsManager ).InnerText.Trim();
                            string imagePath =
                                imageUri.Substring( imageUri.LastIndexOf( "//", StringComparison.OrdinalIgnoreCase ) + 2 );
                            string imageFile = Path.Combine( path, imagePath );
                            using ( FileStream fileStream = new FileStream( imageFile, FileMode.Open, FileAccess.Read )
                                )
                            {
                                Byte[] bitmapData = new byte[fileStream.Length];
                                fileStream.Read( bitmapData, 0, (int) fileStream.Length );
                                image.ResourceBytes = bitmapData;
                            }
                        }
                        topic.Resources.Add( image );


                        break;
                    }
                }
            }

            XmlNode notesNode = node.SelectSingleNode( "./ap:NotesGroup/ap:NotesXhtmlData", nsManager );
            if ( notesNode != null )
            {
                using (
                    MemoryStream stream =
                        new MemoryStream(
                            Encoding.Default.GetBytes( HtmlToXamlConverter.ConvertHtmlToXaml( notesNode.InnerXml, true ) ) )
                    )
                {
                    FlowDocument doc = (FlowDocument) XamlReader.Load( stream );

                    topic.Note = new TextRange( doc.ContentStart, doc.ContentEnd );
                }
            }

            XmlNodeList subNodes = node.SelectNodes( "./ap:SubTopics/ap:Topic", nsManager );
            if ( subNodes != null && subNodes.Count > 0 )
            {
                foreach ( XmlNode subNode in subNodes )
                {
                    Topic subTopic = new Topic();
                    subTopic.Parent = topic;
                    topic.SubTopics.Add( subTopic );
                    ParseNode( subNode, nsManager, subTopic, path );
                }
            }
        }

        private static XmlNamespaceManager CreateListItemNsMgr( XmlNameTable nameTable )
        {
            XmlNamespaceManager nsmgr = new XmlNamespaceManager( nameTable );
            nsmgr.AddNamespace( "ap", "http://schemas.mindjet.com/MindManager/Application/2003" );
            nsmgr.AddNamespace( "cor", "http://schemas.mindjet.com/MindManager/Core/2003" );

            return nsmgr;
        }

        public override AddinInfo Info
        {
            get
            {
                AddinInfo info = new AddinInfo();
                info.Name = "Mind Manager";
                info.Group = "Import";
                info.Description = "Import a mind map from MindManager file";
                info.Image = AssemblyUtility.LoadImageFromResources(
                    typeof ( MindManagerImportAddin ).Assembly, "Bookvar.AddIns.MindManagerImport.MMImport.png" );

                return info;
            }
        }
    }
}